"""
npm包自动发布脚本
功能：
1. 自动更新版本号（格式：年份后两位.月份.自增编号）
2. 从环境变量或.npmrc文件获取npm token
3. 执行npm publish命令发布包
"""

import os
import subprocess
from pathlib import Path
import json
from datetime import datetime


def get_npm_token():
    """
    获取npm发布token
    获取顺序：
    1. 优先从NPM_TOKEN环境变量获取
    2. 其次从用户主目录的.npmrc文件获取
    返回: str - npm token字符串
    异常: 如果都找不到则抛出ValueError
    """
    # 首先尝试从环境变量获取
    if 'NPM_TOKEN' in os.environ:
        return os.environ['NPM_TOKEN']

    # 然后尝试从.npmrc文件获取
    npmrc_path = Path.home() / '.npmrc'
    if npmrc_path.exists():
        with open(npmrc_path, 'r') as f:
            for line in f:
                if line.startswith('//registry.npmjs.org/:_authToken='):
                    return line.split('=')[1].strip()

    raise ValueError("无法找到npm token - 请设置NPM_TOKEN环境变量或在.npmrc文件中配置token")


def update_version():
    """
    自动更新package.json中的版本号
    版本号格式规则：
    - 第一部分：当前年份后两位(如2025年显示为25)
    - 第二部分：当前月份(不补零)
    - 第三部分：自增编号(同月内递增，跨月重置为1)

    返回: bool - 是否成功更新
    异常: 如果操作失败则打印错误并返回False
    """

    try:
        # 读取package.json
        with open('package.json', 'r') as f:
            package = json.load(f)

        # 获取当前日期
        now = datetime.now()
        year = str(now.year)[-2:]  # 年份后两位
        month = str(now.month)      # 月份不补零

        # 解析现有版本号
        if 'version' in package:
            current_version = package['version'].split('.')
            if len(current_version) == 3 and current_version[0] == year and current_version[1] == month:
                # 如果年份和月份相同，则递增第三位
                build_num = int(current_version[2]) + 1
            else:
                # 如果年份或月份不同，则重置为1
                build_num = 1
        else:
            # 如果没有版本号，初始化为1
            build_num = 1

        new_version = f"{year}.{month}.{build_num}"
        package['version'] = new_version
        # 写回package.json
        with open('package.json', 'w') as f:
            json.dump(package, f, indent=2)

        print(f"版本号已更新至: {new_version}")
        return new_version

    except Exception as e:
        print(f"更新版本号失败: {str(e)}")
        exit(0)


def publish_to_npm():
    """
    执行npm发布流程
    步骤：
    1. 调用update_version()更新版本号
    2. 调用get_npm_token()获取token
    3. 设置环境变量
    4. 执行npm publish命令

    异常: 捕获并打印所有过程中的错误
    """
    try:
        version = update_version()

        token = get_npm_token()
        env = os.environ.copy()
        env['NPM_TOKEN'] = token

        # 修改为使用shell=True确保能找到npm
        result = subprocess.run(
            'npm publish --registry=https://registry.npmjs.org',
            env=env,
            cwd=os.getcwd(),
            shell=True,
            capture_output=True,
            text=True
        )

        if result.returncode == 0:
            print("发布成功！")
            print(result.stdout)

            # 添加5秒延迟等待CDN同步
            print("等待5秒让npm CDN同步最新版本...")
            import time
            time.sleep(5)

            # 使用具体版本号进行全局安装
            print(f"开始全局安装ykvue@{version}...")
            max_retries = 10
            for attempt in range(max_retries):
                print(f"尝试 {attempt + 1}/{max_retries}...")
                install_result = subprocess.run(
                        f'npm install -g ykvue@{version} --registry=https://registry.npmjs.org',
                        env=env,
                        cwd=os.getcwd(),
                        shell=True,
                        capture_output=True,
                        text=True
                    )
                if install_result.returncode == 0:
                    print(f"全局安装ykvue@{version}成功！")
                    print(install_result.stdout)
                    break
                else:
                    print(f"安装尝试失败，错误信息:")
                    print(install_result.stderr)
                    if attempt < max_retries - 1:
                        print(f"等待5秒后重试...")
                        time.sleep(5)
            else:
                print(f"经过{max_retries}次尝试后仍无法安装ykvue@{version}")
        else:
            print("发布失败！")
            print(result.stderr)

    except Exception as e:
        print(f"发布过程中出错: {str(e)}")


if __name__ == '__main__':
    """
    脚本入口点
    直接调用publish_to_npm()开始发布流程
    """
    publish_to_npm()
